﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.XPath;

namespace InfoPathHelpers.Cryptography.Encoding
{
    /// <summary>
    /// Used to encode the values of elements within an XPathNavigator to base64.
    /// </summary>
    class ElementEncoder
    {
        /// <summary>
        /// Creates a new instance of the ElementEncode class.
        /// </summary>
        public ElementEncoder()
        {
            NodesToIgnore = new List<string>();
            GroupsToIgnore = new List<string>();
        }

        /// <summary>
        /// Creates a new instance of the ElementEncode class using the supplied lists of nodes/groups to ignore.
        /// </summary>
        public ElementEncoder(List<string> nodesToIgnore, List<string> groupsToIgnore)
        {
            NodesToIgnore = nodesToIgnore;
            GroupsToIgnore = groupsToIgnore;
        }

        /// <summary>
        /// Gets or sets the list of local names for nodes which should not be processed during encryption/decryption.
        /// </summary>
        public List<string> NodesToIgnore { get; set; }

        /// <summary>
        /// Gets or sets the list of local names for groups which should not be processed during encryption/decryption.
        /// </summary>
        public List<string> GroupsToIgnore { get; set; }

        /// <summary>
        /// Encodes the value of the supplied node to Base64.
        /// </summary>
        /// <param name="node">The node to encode.</param>
        public static void EncodeBase64Node(XPathNavigator node)
        {
            // return if the node is null or has no value.
            if (node == null || string.IsNullOrEmpty(node.Value))
                return;
            // Encode the node.Value to Base64.
            byte[] Bytes = System.Text.Encoding.UTF8.GetBytes(node.Value);
            string Base64 = Convert.ToBase64String(Bytes);
            // Set the value on the node to the encoded string.
            node.SetValue(Base64);
        }

        /// <summary>
        /// Decodes the value of the supplied node from Base64.
        /// </summary>
        /// <param name="node">The node to decode.</param>
        public static void DecodeBase64Node(XPathNavigator node)
        {
            // return if the node is null or has no value.
            if (node == null || string.IsNullOrEmpty(node.Value))
                return;
            // Decode the node.Value from Base64.
            byte[] Bytes = Convert.FromBase64String(node.Value);
            string Value = System.Text.Encoding.UTF8.GetString(Bytes);
            // Set the value on the node to the decoded string.
            node.SetValue(Value);
        }

        /// <summary>
        /// Encodes the values of all child elements and attributes of the supplied node to Base64
        /// except those with local names matching those in the NodesToIgnore and GroupsToIgnore lists.
        /// </summary>
        /// <param name="rootNode">The node who children are to be encoded.</param>
        public void EncodeChildNodes(XPathNavigator rootNode)
        {
            NodeHelpers.ProcessAllNodes(rootNode, NodesToIgnore, GroupsToIgnore, EncodeBase64Node);
        }

        /// <summary>
        /// Decodes the values of all child elements and attributes of the supplied node from Base64
        /// except those with local names matching those in the NodesToIgnore and GroupsToIgnore lists.
        /// </summary>
        /// <param name="rootNode">The node who children are to be decoded.</param>
        public void DecodeChildNodes(XPathNavigator rootNode)
        {
            NodeHelpers.ProcessAllNodes(rootNode, NodesToIgnore, GroupsToIgnore, DecodeBase64Node);
        }
    }
}
